#pragma once

#include "tstring.h"
#include "Time.h"
#include <map>

/*	
 	information sources:
 *	About time zone database http://www.codeproject.com/KB/dotnet/WorldClock.aspx
 *  About doomsday rule http://www.codeproject.com/KB/datetime/doomsdaydate.aspx
 *	About DynamicDST (DYNAMIC_TIME_ZONE_INFORMATION) http://msdn.microsoft.com/en-us/library/ms724253(VS.85).aspx
 *	The bias, standardBias and daylightBias fields follow the rule: UTC = local + bias + daylight bias if summer time.

 *	!!! Before using this library read
		http://blogs.technet.com/dst2007/archive/2007/03/11/time-zones-not-updating-on-windows-2003-windows-xp-or-windows-2000.aspx
	and http://support.microsoft.com/kb/951072/

 *  !!! Day value in the standard date and daylight date values is an N-th sunday from 1-th of month. Not the real day of month!

 *	TZI stands for Time Zone Information
 *	local_time stands for local for that time zone time.
 *	Uniquie time zone indexes are taken from registry.
 */

namespace TimeZone
{
	class TimeZone
	{
		//	types

		struct StandardRange
		{
			Time			m_start;	// when standard time begins.
			Time			m_end;		// when daylight saving time begins

			//	m_start_time and m_end_time contents:
			//		year is always zero
			//		month is valid
			//		the number of sunday in month instead of months day
			//		hours, minute and seconds are valid
			//	Exaple: 0000/10/05 03:00:00:000 - October, 5-th sunday, 03:00:00

			static void		_timeFromRangeBorder(const Time& border, int year, Time* dest);
			static void		_yearStart(int year, Time* dest);

			StandardRange(void);
			void			clear(void);
			void			print(const _tstring& prefix) const;
			bool			inRange(const Time& local_time) const;
			int				hitWithinYear(const Time& local_time, Time* start_at, Time* expires_at) const;
		};

		struct TZI
		{
			int				m_bias;
			int				m_standard_bias;
			int				m_daylight_bias;
			StandardRange	m_standard_range;

			TZI(void);
			void			fill(TIME_ZONE_INFORMATION* dest) const;
			void			clear(void);
			void			print(const _tstring& prefix) const;
		};

		typedef std::map<int/*year*/, TZI> DynamicDST;

		//	data

		_tstring			m_display_name;
		_tstring			m_standard_name;
		_tstring			m_daylight_name;
		int					m_unique_index;
		TZI					m_tzi;
		DynamicDST			m_dsts;

		//	methods

		static bool			_loadTimeZone(HKEY root_key, const wchar_t* name, TimeZone* dest);
		static bool			_loadDynamicDst(HKEY tz_key, DynamicDST* dest);
		static bool			_loadString(HKEY key, const wchar_t* name, _tstring* dest);

		const TZI&			_tziFor(const Time& local_time) const;

	public:
		TimeZone(void);
		~TimeZone(void);

		void				clear(void);
		void				print(const _tstring& prefix) const;

		int					biasMinutes(const Time& local_time, Time* started_at = 0, Time* expired_at = 0) const;
		int					biasSeconds(int utc, int* started_at_utc = 0, int* expired_at_utc = 0) const;
		void				toUniversalTime(Time& local_time, Time* universal) const;
		bool				isStandardTime(const Time& local_time) const;

		static	void		enumZones(void);
		static	bool		getZone(int index, TimeZone* dest);
	};
} // namespace TimeZone